import {Injectable} from '@angular/core';
import {AppConfig} from '../../config';
import {WebSocketService} from './websocket.service';
import {TagProtocol} from './tag-protocol';
import {Subject} from 'rxjs/Subject';
import {MatrixData} from '../../entity/matrix-data';
import {TagData} from '../../entity/tag-data.model';
import {FaultData} from '../../entity/fault-data';
import {Session} from './session';
import {SubstationData} from '../../entity/substation-data';

/**
 * 即时通信传送推服务（Instant Messaging）
 *
 * @export
 * @class IMPushService
 */
@Injectable()
export class IMPushTestService {
  /**
   * 时间格式化字符串
   *
   * @private
   * @type {string}
   * @memberof IMPushTestService
   */
  private fomat: string = 'yyyy-MM-dd HH:mm:ss';

  /**
   * websocket通信地址
   *
   * @private
   * @type {string}
   * @memberof IMPushService
   */
  private get url(): string {
    return AppConfig.APP_WEBSOCKET;
  }


  /**
   * 服务ws集合
   *
   * @private
   * @type {session[]}
   * @memberof IMPushService
   */
  private WebSockets: WebSocket[] = [];

  /**
   * 服务session集合
   *
   * @private
   * @type {session[]}
   * @memberof IMPushService
   */
  private sessionMap: Session[] = [];

  /**
   * Creates an instance of IMPushService.
   * @memberof IMPushService
   */
  constructor() {
    let self = this;
    //监听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。
    window.onbeforeunload = function () {
      self.close();
    }
  }

  /**
   * 开始订阅测点实时数据
   * (首先返回测点快照值，其后服务端开启数据订阅，数据变化时推送到客户端)
   *
   * @returns {Subject<any>}
   * @memberof IMPushService
   */
  public begin(protocol: TagProtocol): Subject<TagData[]> {
    // 隐藏字段
    protocol.setDefineProperty();
    Object.defineProperty(protocol, 'endTime', {enumerable: false});
    Object.defineProperty(protocol, 'startTime', {enumerable: false});
    Object.defineProperty(protocol, 'historyInterval', {enumerable: false});
    Object.defineProperty(protocol, 'pushInterval', {enumerable: false});
    return this.common(`${this.url}/realtimeServer`, protocol);
  }

  public interval(protocol: TagProtocol, interval: number): Subject<TagData[]> {
    // 隐藏字段
    protocol.setDefineProperty();
    Object.defineProperty(protocol, 'endTime', {enumerable: false});
    Object.defineProperty(protocol, 'startTime', {enumerable: false});
    Object.defineProperty(protocol, 'historyInterval', {enumerable: false});
    Object.defineProperty(protocol, 'pushInterval', {enumerable: true});
    return this.common(`${this.url}/realtimeServer`, protocol);
  }

  public withHistories(protocol: TagProtocol, start: Date, end: Date): Subject<any>;
  public withHistories(protocol: TagProtocol, start: Date, end: Date, interval: number): Subject<any>;
  public withHistories(protocol: TagProtocol, start: Date, end: Date, interval: { history: number; push: number; }): Subject<any>;
  public withHistories(protocol: TagProtocol, start: Date, end: Date, interval?: any): Subject<any> {
    protocol.startTime = start;
    protocol.endTime = end;
    if (interval != null) {
      if (typeof interval == 'number') {
        protocol.historyInterval = interval;
        protocol.setDefineProperty();
        Object.defineProperty(protocol, 'pushInterval', {enumerable: false});
        Object.defineProperty(protocol, 'historyInterval', {enumerable: true});
        return this.common(`${this.url}/realtimeServer`, protocol);
      } else if (typeof interval == 'object') {
        protocol.pushInterval = interval.push;
        protocol.historyInterval = interval.history;
        protocol.setDefineProperty();
        Object.defineProperty(protocol, 'historyInterval', {enumerable: true});
        Object.defineProperty(protocol, 'pushInterval', {enumerable: true});
        return this.common(`${this.url}/realtimeServer`, protocol);
      }
    } else {
      protocol.setDefineProperty();
      Object.defineProperty(protocol, 'historyInterval', {enumerable: false});
      Object.defineProperty(protocol, 'pushInterval', {enumerable: false});
      return this.common(`${this.url}/realtimeServer`, protocol);
    }

  }

  /**
   * 公共的WebSocket调用方法
   *
   * @private
   * @param {string} url
   * @param {string} session
   * @param {*} sendData
   * @returns {Subject<any>}
   * @memberof IMPushService
   */
  private common(url: string, sendData: any): Subject<any> {
    let subject = new Subject<any>();
    // 用于发送点名
    const sendSocket = new WebSocketService(url);
    sendSocket.onError((ev: Event) => {
      // console.log('IMPushService (sendSocket) onError', ev);
    });
    sendSocket.onClose((ev: CloseEvent) => {
      //console.log('IMPushService (sendSocket) onClose', ev.code);
      // 关闭订阅
      subject.unsubscribe();
      subject = null;
    });
    sendSocket.onOpen((ev: Event) => {
      //console.log('IMPushService (sendSocket) onOpen', sendData);
      let respondSelf: WebSocket = ev.currentTarget as WebSocket;
      if (sendData != null) {
        respondSelf.send(JSON.stringify(sendData));
      }
      this.WebSockets.push(respondSelf);
    });
    sendSocket.onMessage((msg: MessageEvent) => {
      if (msg.data) {
        if (subject != null && !subject.closed && !subject.isStopped) {
          subject.next(JSON.parse(msg.data));
          // const obj: Object = data[0];
          // if (!data.length) {
          //   subject.next(data);
          // } else if (data.hasOwnProperty('segment')) {
          //   const segment: { segment: number } = data;
          //   subject.next(segment);
          // } else if (obj.hasOwnProperty('faultCode')) {
          //   const faultDatas: FaultData[] = data;
          //   subject.next(faultDatas);
          // } else if (obj.hasOwnProperty('stateId')) {
          //   const matrixDatas: MatrixData[] = data;
          //   subject.next(matrixDatas);
          // } else if (obj.hasOwnProperty('stationTagCode')) {
          //   const substationData: SubstationData[] = data;
          //   subject.next(substationData);
          // } else if (obj.hasOwnProperty('code')) {
          //   const tagDatas: TagData[] = data;
          //   subject.next(tagDatas);
          // } else {
          //   const tagDatas: DeviceAlarm[] = data;
          // subject.next(tagDatas);
          // }
        }
      }
    });
    return subject;
  }


  /**
   * 订阅风机矩阵数据
   *
   * @param {{tagId: number,farmIds: number[]}} matrix
   * @returns {Subject<any>}
   * @memberof IMPushService
   */
  public matrix(matrix: { tagId: number, farmIds: number[] }): Subject<MatrixData[]> {
    return this.common(`${this.url}/matrixServer`, [matrix]);
  }

  /**
   * 订阅风机报警数据
   *
   * @param {number} userId
   * @returns {Subject<FaultData[]>}
   * @memberof IMPushService
   */
  public alarm(keys: number[], type: number): Subject<FaultData[]> {
    return this.common(`${this.url}/alarmServer`, {
      keys: keys,
      type: type
    });
  }

  public sendMessage(message: string): void {
    if (this.WebSockets.length > 0) {
      this.WebSockets[0].send(message);
    }
  }

  /**
   * 订阅升压站数据
   *
   * @param {number} userId
   * @returns {Subject<SubstationData[]>}
   * @memberof IMPushService
   */
  public substation(userId: number): Subject<SubstationData[]> {
    return this.common(`${this.url}/stationServer`, userId);
  }

  /**
   *开始订阅历史报警数据
   *
   * @param {number[]} farmIds
   * @returns {Subject<FaultData[]>}
   * @memberof IMPushTestService
   */
  public alarmHistory(startTime, endTime, deviceIds: number[]): Subject<FaultData[]> {
    const tagArrary = deviceIds.map(d => d.toString());
    return this.common(`${this.url}/historyAlarmServer`, {
      startTime: startTime,
      endTime: endTime,
      tagArrary: tagArrary
    });
  }

  /**
   * 关闭
   *
   * @memberof IMPushService
   */
  public close() {
    this.WebSockets.forEach(ws => {
      if (ws.readyState === 1)
        ws.close();
    });
    this.sessionMap.forEach(session => {
      //如果通道没关闭
      if (session.socket.socket.readyState === 1) {
        let closeSocket = new WebSocketService(`${this.url}/${session.closeServerChannelName}`);
        closeSocket.onOpen((ev: Event) => {
          ///console.log('(closeSocket) onOpen', ev);
          let selfCloseWebSocket = ev.currentTarget as WebSocket;
          //发送关闭指令
          selfCloseWebSocket.send(`${session.serverChannelName},${session.sessionId},${session.stopCommand}`);
        });
        closeSocket.onMessage((ev: MessageEvent) => {
          /// console.log('(closeSocket) onMessage', ev.data);
          let selfCloseWebSocket = ev.currentTarget as WebSocket;

          selfCloseWebSocket.close();
          //强制关闭
          if (session.socket.socket.readyState == 1) {
            session.socket.socket.close();
          }
        });
        closeSocket.onClose((ev: CloseEvent) => {
          ///console.log('(closeSocket) onClose', ev.code);
        });
        closeSocket.onError((ev: Event) => {
          ///console.log('(closeSocket) onError', ev);
        });
      }
    });
  }
}
